package emulator.hardware.io.peripherals.iec;

import java.util.HashMap;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.prefs.Preferences;

public class IecSimDeviceRegistry extends Observable implements Observer {
	private Map<Integer, DeviceInfo> device_map = null;
	private static IecSimDeviceRegistry instance = new IecSimDeviceRegistry();
	private Preferences cfg = null;
	
	private IecSimDeviceRegistry()
	{
	    cfg  = Preferences.userNodeForPackage(this.getClass());
		loadConfiguration();
	}
	
	public static IecSimDeviceRegistry instance()
	{
		return instance;
	}

	public void loadConfiguration() {
		device_map = new HashMap<Integer, DeviceInfo>();
		String device_list = cfg.get("iec_devices", "?");
		if (device_list.equals("?"))
		{	// default
			addDeviceInt(new DeviceInfo(4, DeviceInfo.PRINTER, "(null)"));
			addDeviceInt(new DeviceInfo(8, DeviceInfo.DISK, "."));
		}
		else
		{
			String[] devices = device_list.split(",");
			for (int i = 0; i < devices.length; i++)
			{
				if (devices[i].length() > 0)
				{
					String device_config = cfg.get("iec_device_"+devices[i], "");
					DeviceInfo device = DeviceInfo.fromConfig(device_config);
					if (device != null && !device_map.containsKey(device.getAddress()))
						addDeviceInt(device);
				}
			}
		}
		setChanged();
		notifyObservers();
	}
	
	public void saveConfiguration() {
		String device_list = "";
		for (DeviceInfo device : device_map.values())
		{
			String dev_key = ""+device.getAddress();
			cfg.put("iec_device_"+dev_key, device.toConfig());
			device_list += dev_key+",";
		}
		cfg.put("iec_devices", device_list);
	}
	
	public void addDevice(DeviceInfo device)
	{
		addDeviceInt(device);
		update(this, device);
	}

	private void addDeviceInt(DeviceInfo device) {
		device.addObserver(this);
		device_map.put(device.getAddress(), device);
	}
	
	public void removeDevice(DeviceInfo device)
	{
		if (device != null)
		{
			device.deleteObserver(this);
			device_map.remove(device.getAddress());
			update(this, device);
		}
	}
	
	public int [] enumDevices()
	{
		int [] device_numbers = new int [device_map.size()];
		int cur_idx = 0;
		for (Integer number : device_map.keySet())
		{
			device_numbers[cur_idx++] = number;
		}
		return device_numbers;
	}

	@Override
	public void update(Observable arg0, Object arg1) {
		saveConfiguration();
		setChanged();
		notifyObservers();
	}

	public DeviceInfo getDevice(int number) {
		return device_map.get(number);
	}

	public Integer[] getAvailableDeviceNumbers() {
		Integer [] device_numbers = new Integer [28 - device_map.size()];
		int idx = 0;
		for (int number = 4; number < 32; number++)
		{
			if (!device_map.containsKey(number))
				device_numbers[idx++] = number;
		}
		return device_numbers;
	}
}
